home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / sun4.md / devXylogics450.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  51KB  |  1,675 lines

  1. /* 
  2.  * devXylogics450.c --
  3.  *
  4.  *    Driver the for Xylogics 450 SMD controller.
  5.  *    The technical
  6.  *    manual to refer to is "XYLOGICS 450 Disk Controller User's Manual".
  7.  *    (Date Aug 1983, Rev. B)
  8.  *
  9.  * Copyright 1989 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/sun4.md/devXylogics450.c,v 9.7 91/09/10 18:20:16 rab Exp $ SPRITE (Berkeley)";
  21. #endif /* not lint */
  22.  
  23. #include "sprite.h"
  24. #include "mach.h"
  25. #include "dev.h"
  26. #include "devInt.h"
  27. #include "devDiskLabel.h"
  28. #include "dbg.h"
  29. #include "vm.h"
  30. #include "sys.h"
  31. #include "sync.h"
  32. #include "fs.h"
  33. #include "vmMach.h"
  34. #include "devQueue.h"
  35. #include "devBlockDevice.h"
  36. #include "xylogics450.h"
  37. #include "devDiskStats.h"
  38. #include "stdio.h"
  39. #include "stdlib.h"
  40. #include "bstring.h"
  41. /*
  42.  * RANDOM NOTES:
  43.  *
  44.  * The Xylogics board does crazed address relocation, either to 20-bit
  45.  * or 24-bit addresses.  I expect only 24-bit mode with the sun3's,
  46.  * which means the top half of the DVMA addresses has to be cropped
  47.  * off and put in the relocation register part of the IOPB
  48.  *
  49.  * The IOPB format must be byte swapped with respect to the documentation
  50.  * because of disagreement between the multibus/8086 ordering and the
  51.  * sun3/Motorola ordering.
  52.  */
  53.  
  54. /*
  55.  * The I/O Registers of the 450 are used to initiate commands and to
  56.  * specify where parameter blocks (IOPB) are.  The bytes are swapped
  57.  * because the controller thinks it's on a multibus.
  58.  */
  59. typedef struct XylogicsRegs {
  60.     char relocHigh;    /* Byte 1 - IOPB Relocation Register High Byte */
  61.     char relocLow;    /* Byte 0 - IOPB Relocation Register Low Byte */
  62.     char addrHigh;    /* Byte 3 - IOPB Address Register High Byte */
  63.     char addrLow;    /* Byte 2 - IOPB Address Register Low Byte */
  64.     char resetUpdate;    /* Byte 5 - Controller Reset/Update Register */
  65.     char status;    /* Byte 4 - Controller Status Register (CSR) */
  66. } XylogicsRegs;
  67.  
  68. /*
  69.  * Definitions for the bits in the status register
  70.  *    XY_GO_BUSY    - set by driver to start command, remains set
  71.  *              until the command completes.
  72.  *    XY_ERROR    - set by the controller upon error
  73.  *              Do error reset by setting this bit to 1
  74.  *    XY_DBL_ERROR    - set by controller upon error DMA'ing status bytes.
  75.  *    XY_INTR_PENDING    - set by controller, must be unset by handler
  76.  *              by writing a 1 to it.
  77.  *    XY_20_OR_24    - If zero, the controller does 20 bit relocation,
  78.  *              otherwise it uses the relocation bytes as the
  79.  *              top 16 bits of the DMA address.
  80.  *    XY_ATTN_REQ    - Set when you want to add more IOPB's to the chain,
  81.  *              clear this when work on the chain is complete.
  82.  *    XY_ATTN_ACK    - Set by the controller when it's safe to add/delete
  83.  *              IOPB's to the command chain.
  84.  *    XY_READY    - "Indicates the Ready-On Cylinder status of the
  85.  *              last drive selected.
  86.  */
  87. #define    XY_GO_BUSY    0x80
  88. #define XY_ERROR    0x40
  89. #define XY_DBL_ERROR    0x20
  90. #define XY_INTR_PENDING    0x10
  91. #define    XY_20_OR_24    0x08
  92. #define XY_ATTN_REQ    0x04
  93. #define XY_ATTN_ACK    0x02
  94. #define XY_READY    0x01
  95.  
  96. typedef struct XylogicsIOPB {
  97.     /*
  98.      * Byte 1 - Interrupt Mode
  99.      */
  100.     unsigned char        :1;
  101.     unsigned char intrIOPB    :1;    /* Interrupt upon completion of IOPB */
  102.     unsigned char intrError    :1;    /* Interrupt upon error (440 only) */
  103.     unsigned char holdDualPort    :1;    /* Don't release dual port drive */
  104.     unsigned char autoSeekRetry    :1;    /* Enables re-calibration on error */
  105.     unsigned char enableExtras    :1;    /* Enables commands 3 and 4 */
  106.     unsigned char eccMode    :2;    /* ECC Correction Mode, set to 2 */
  107.     /*
  108.      * Byte 0 - Command Byte
  109.      */
  110.     unsigned char autoUpdate    :1;    /* Update IOPB after completion */
  111.     unsigned char relocation    :1;    /* Enables relocation on data addrs */
  112.     unsigned char doChaining    :1;    /* Enables chaining of IOPBs */
  113.     unsigned char interrupt    :1;    /* When set interupts upon completion */
  114.     unsigned char command    :4;    /* Commands defined below */
  115.     /*
  116.      * Byte 3 - Status Byte 2
  117.      */
  118.     unsigned char errorCode;    /* Error codes, 0 means success, the rest
  119.                  * of the codes are explained in the manual */
  120.     /*
  121.      * Byte 2 - Status Byte 1
  122.      */
  123.     unsigned char error        :1;    /* Indicates an error occurred */
  124.     unsigned char         :2;
  125.     unsigned char cntrlType    :3;    /* Controller type, 1 = 450 */
  126.     unsigned char        :1;
  127.     unsigned char done        :1;    /* Command is complete */
  128.     /*
  129.      * Byte 5 - Drive Type, Unit Select
  130.      */
  131.     unsigned char driveType    :2;    /* 2 => Fujitsu 2351 (Eagle) */
  132.     unsigned char        :4;
  133.     unsigned char unit        :2;    /* Up to 4 drives per controller */
  134.     /*
  135.      * Byte 4 - Throttle
  136.      */
  137.     unsigned char transferMode    :1;    /* == 0 for words, 1 for bytes */
  138.     unsigned char interleave    :4;    /* == 0 for 1:1 interleave */
  139.     unsigned char throttle    :3;    /* 4 => 32 words per DMA burst */
  140.  
  141.     unsigned char sector;    /* Byte 7 - Sector Byte */
  142.     unsigned char head;        /* Byte 6 - Head Byte */
  143.     unsigned char cylHigh;    /* Byte 9 - High byte of cylinder address */
  144.     unsigned char cylLow;    /* Byte 8 - Low byte of cylinder address */
  145.     unsigned char numSectHigh;    /* Byte B - High byte of sector count */
  146.     unsigned char numSectLow;    /* Byte A - Low byte of sector count.
  147.                  * This byte is also used to return status
  148.                  * with the Read Drive Status command */
  149.     /*
  150.      * Don't byteswap the data address and relocation offset.  All the
  151.      * byte-swapped device is going to do is turn around and put these
  152.      * addresses back onto the bus, so don't have to worry about ordering.
  153.      * (The relocation register is scary, but the Sun MMU puts all the
  154.      * DMA buffer space into low physical memory addresses, so the relocation
  155.      * register is probably zero anyway.)
  156.      */
  157.     unsigned char dataAddrHigh;    /* Byte D - High byte of data address */
  158.     unsigned char dataAddrLow;    /* Byte C - Low byte of data address */
  159.     unsigned char relocHigh;    /* Byte F - High byte of relocation value */
  160.     unsigned char relocLow;    /* Byte E - Low byte of relocation value */
  161.     /*
  162.      * Back to byte-swapping
  163.      */
  164.     unsigned char reserved1;    /* Byte 11 */
  165.     unsigned char headOffset;    /* Byte 10 */
  166.     unsigned char nextHigh;    /* Byte 13 - High byte of next IOPB address */
  167.     unsigned char nextLow;    /* Byte 12 - Low byte of next IOPB address */
  168.     unsigned char eccByte15;    /* Byte 15 - ECC Pattern byte 15 */
  169.     unsigned char eccByte14;    /* Byte 14 - ECC Pattern byte 14 */
  170.     unsigned char eccAddrHigh;    /* Byte 17 - High byte of sector bit address */
  171.     unsigned char eccAddrLow;    /* Byte 16 - Low byte of sector bit address */
  172. } XylogicsIOPB;
  173.  
  174. #define XYLOGICS_MAX_CONTROLLERS    2
  175. #define XYLOGICS_MAX_DISKS        4
  176.  
  177. /*
  178.  * Defines for the command field of Byte 0. These are explained in
  179.  * pages 25 to 58 of the manual.  The code here uses READ and WRITE, of course,
  180.  * and also XY_RAW_READ to learn the proper drive type, and XY_READ_STATUS
  181.  * to see if a drive exists.
  182.  */
  183. #define XY_NO_OP        0x0
  184. #define XY_WRITE        0x1
  185. #define XY_READ            0x2
  186. #define XY_WRITE_HEADER        0x3
  187. #define XY_READ_HEADER        0x4
  188. #define XY_SEEK            0x5
  189. #define XY_DRIVE_RESET        0x6
  190. #define XY_WRITE_FORMAT        0x7
  191. #define XY_RAW_READ        0x8
  192. #define XY_READ_STATUS        0x9
  193. #define XY_RAW_WRITE        0xA
  194. #define XY_SET_DRIVE_SIZE    0xB
  195. #define XY_SELF_TEST        0xC
  196. /*      reserved          0xD */
  197. #define XY_BUFFER_LOAD        0xE
  198. #define XY_BUFFER_DUMP        0xF
  199.  
  200. /*
  201.  * Defines for error code values.  They are explained fully in the manual.
  202.  */
  203. #define XY_NO_ERROR        0x00
  204. /*
  205.  * Programming errors
  206.  */
  207. #define XY_ERR_INTR_PENDING    0x01
  208. #define XY_ERR_BUSY_CONFLICT    0x03
  209. #define XY_ERR_BAD_CYLINDER    0x07
  210. #define XY_ERR_BAD_SECTOR    0x0A
  211. #define XY_ERR_BAD_COMMAND    0x15
  212. #define XY_ERR_ZERO_COUNT    0x17
  213. #define XY_ERR_BAD_SECTOR_SIZE    0x19
  214. #define XY_ERR_SELF_TEST_A    0x1A
  215. #define XY_ERR_SELF_TEST_B    0x1B
  216. #define XY_ERR_SELF_TEST_C    0x1C
  217. #define XY_ERR_BAD_HEAD        0x20
  218. #define XY_ERR_SLIP_SECTOR    0x09
  219. #define XY_ERR_SLAVE_ACK    0x0E
  220. /*
  221.  * Soft errors that may be recovered by retrying.  Retry at most twice.
  222.  */
  223. #define XY_SOFT_ERR_TIME_OUT    0x04
  224. #define XY_SOFT_ERR_BAD_HEADER    0x05
  225. #define XY_SOFT_ERR_ECC        0x06
  226. #define XY_SOFT_ERR_NOT_READY    0x16
  227. /*
  228.  * These errors cause a drive re-calibration, then you retry the transfer.
  229.  */
  230. #define XY_SOFT_ERR_HEADER    0x12
  231. #define XY_SOFT_ERR_FAULT    0x18
  232. #define XY_SOFT_ERR_SEEK    0x25
  233. /*
  234.  * Errors during formatting.
  235.  */
  236. #define XY_FORMAT_ERR_RUNT    0x0D
  237. #define XY_FORMAT_ERR_BAD_SIZE    0x13
  238. /*
  239.  * Noteworthy errors.
  240.  */
  241. #define XY_WRITE_PROTECT_ON    0x14
  242. #define XY_SOFT_ECC_RECOVERED    0x1F
  243. #define XY_SOFT_ECC        0x1E
  244.  
  245. /*
  246.  * Bit values for the numSectLow byte used to return Read Drive Status
  247.  *    XY_ON_CYLINDER        == 0 if drive is not seeking
  248.  *    XY_DISK_READY        == 0 if drive is ready
  249.  *    XY_WRITE_PROTECT    == 1 if write protect is on
  250.  *    XY_DUAL_PORT_BUSY    == 1 if dual ported drive is busy
  251.  *    XY_HARD_SEEK_ERROR    == 1 if the drive reports a seek error
  252.  *    XY_DISK_FAULT        == 1 if the drive reports any kind of fault
  253.  */
  254. #define XY_ON_CYLINDER        0x80
  255. #define XY_DISK_READY        0x40
  256. #define XY_WRITE_PROTECT    0x20
  257. #define XY_DUAL_PORT_BUSY    0x10
  258. #define XY_HARD_SEEK_ERROR    0x80
  259. #define XY_DISK_FAULT        0x40
  260.  
  261. /*
  262.  * The XY_RAW_READ and XY_RAW_WRITE commands return sector header
  263.  * information that looks like the following struct.  Again, this
  264.  * is byte-swapped in comparison with the documentation.
  265.  *
  266.  * A raw read is done during boot strap to determine the drive type.
  267.  * The label is read at the same time to determine the disk geometry,
  268.  * and this information is passed back into the controller.
  269.  */
  270. typedef struct XylogicsSectorHeader {
  271.     /*
  272.      * Byte 1
  273.      */
  274.     char sectorHigh    :2;
  275.     char reserved    :3;
  276.     char cylHigh    :3;
  277.     /*
  278.      * Byte 0
  279.      */
  280.     char cylLow        :8;
  281.     /*
  282.      * Byte 3
  283.      */
  284.     char driveType    :2;
  285.     char sectorLow    :6;
  286.     /*
  287.      * Byte 2
  288.      */
  289.     char head        :8;
  290. } XylogicsSectorHeader;
  291.  
  292.  
  293. typedef struct XylogicsDisk XylogicsDisk;
  294. typedef struct Request    Request;
  295.  
  296. typedef struct XylogicsController {
  297.     int            magic;        /* To catch bad pointers */
  298.     Boolean        busy;        /* TRUE if the controller is busy. */
  299.     volatile XylogicsRegs *regsPtr;    /* Pointer to Controller's registers */
  300.     int            number;        /* Controller number, 0, 1 ... */
  301.     Request        *requestPtr;    /* Current active request. */
  302.     Address        dmaBuffer;    /* Address of the DMA buffer
  303.                      * for reads/writes */
  304.     int            dmaBufferSize;    /* Size of the dmaBuffer mapped. */
  305.     volatile XylogicsIOPB *IOPBPtr;    /* Ref to IOPB */
  306.     Sync_Semaphore    mutex;        /* Mutex for queue access */
  307.     Sync_Condition    specialCmdWait; /* Condition to wait of for special
  308.                      * commands liked test unit ready and
  309.                      * reading labels. */
  310.     int            numSpecialWaiting; /* Number of processes waiting to 
  311.                         * get access to the controller for
  312.                         * a sync command. */
  313.     DevCtrlQueues    ctrlQueues;    /* Queues of disk attached to the 
  314.                      * controller. */
  315.     XylogicsDisk    *disks[XYLOGICS_MAX_DISKS]; /* Disk attached to the
  316.                              * controller. */
  317. } XylogicsController;
  318.  
  319. #define XY_CNTRLR_STATE_MAGIC    0xf5e4d3c2
  320.  
  321.  
  322. struct XylogicsDisk {
  323.     int                magic;        /* Check against bad pointers */
  324.     XylogicsController    *xyPtr;    /* Back pointer to controller state */
  325.     int                xyDriveType;    /* Xylogics code for disk */
  326.     int                slaveID;    /* Drive number */
  327.     int                numCylinders;    /* ... on the disk */
  328.     int                numHeads;    /* ... per cylinder */
  329.     int                numSectors;    /* ... on each track */
  330.     DevQueue            queue;
  331.     DevDiskMap            map[DEV_NUM_DISK_PARTS];/* partitions */
  332.     DevDiskStats        *diskStatsPtr;
  333. };
  334.  
  335. #define XY_DISK_STATE_MAGIC    0xa1b2c3d4
  336.  
  337. /*
  338.  * The interface to XylogicsDisk the outside world views the disk as a 
  339.  * partitioned disk.  
  340.  */
  341. typedef struct PartitionDisk {
  342.     DevBlockDeviceHandle handle; /* Must be FIRST field. */
  343.     int    partition;         /* Partition number on disk. */
  344.     XylogicsDisk    *diskPtr; /* Real disk. */
  345. } PartitionDisk;
  346.  
  347. /*
  348.  * Format of request queued for a Xylogics disk. This request is 
  349.  * built in the ctrlData area of the DevBlockDeviceRequest.
  350.  */
  351.  
  352. struct Request {
  353.     List_Links    queueLinks;    /* For the dev queue modole. */
  354.     int        command;    /* XY_READ or XY_WRITE. */
  355.     XylogicsDisk *diskPtr;    /* Target disk for request. */
  356.     Dev_DiskAddr diskAddress;    /* Starting address of request. */
  357.     int        numSectors;    /* Number of sectors to transfer. */
  358.     Address    buffer;        /* Memory to transfer to/from. */
  359.     int        retries;    /* Number of retries on the command. */
  360.     DevBlockDeviceRequest *requestPtr; /* Block device generating this 
  361.                     * request. */
  362. };
  363.  
  364. /*
  365.  * State for each Xylogics controller.
  366.  */
  367. static XylogicsController *xylogics[XYLOGICS_MAX_CONTROLLERS];
  368.  
  369. /*
  370.  * This controlls the time spent busy waiting for the transfer completion
  371.  * when not in interrupt mode.
  372.  */
  373. #define XYLOGICS_WAIT_LENGTH    250000
  374.  
  375. /*
  376.  * SECTORS_PER_BLOCK
  377.  */
  378. #define SECTORS_PER_BLOCK    (FS_BLOCK_SIZE / DEV_BYTES_PER_SECTOR)
  379.  
  380. /*
  381.  * Forward declarations.
  382.  */
  383.  
  384. static void        ResetController();
  385. static ReturnStatus    TestDisk();
  386. static ReturnStatus    ReadDiskLabel();
  387. static void        SetupIOPB();
  388. static ReturnStatus    SendCommand();
  389. static ReturnStatus    GetStatus();
  390. static ReturnStatus    WaitForCondition();
  391. static void         RequestDone();
  392. static void         StartNextRequest();
  393. static void        FillInDiskTransfer();
  394.  
  395.  
  396. /*
  397.  *----------------------------------------------------------------------
  398.  *
  399.  * xyEntryAvailProc --
  400.  *
  401.  *    Act upon an entry becomming available in the queue for a
  402.  *    device.. This routine is the Dev_Queue callback function that
  403.  *    is called whenever work becomes available for a device. 
  404.  *    If the controller is not already busy we dequeue and start the
  405.  *    request.
  406.  *
  407.  * Results:
  408.  *    TRUE if the request is processed. FALSE if the request should be
  409.  *    enqueued.
  410.  *
  411.  * Side effects:
  412.  *    Request may be dequeue and submitted to the device. Request callback
  413.  *    function may be called.
  414.  *
  415.  *----------------------------------------------------------------------
  416.  */
  417.  
  418. static Boolean
  419. xyEntryAvailProc(clientData, newRequestPtr) 
  420.    ClientData    clientData;    /* Really the Device this request ready. */
  421.    List_Links *newRequestPtr;    /* The new request. */
  422. {
  423.     register XylogicsDisk *diskPtr = (XylogicsDisk *) clientData ;
  424.     XylogicsController    *xyPtr = diskPtr->xyPtr;
  425.     register Request    *requestPtr = (Request *) newRequestPtr;
  426.     ReturnStatus    status;
  427.  
  428.     if (xyPtr->busy) {
  429.     return FALSE;
  430.     }
  431.     status = SUCCESS;
  432.     if (requestPtr->numSectors > 0) {
  433.     status = SendCommand(diskPtr, requestPtr, FALSE);
  434.     }
  435.     if (status != SUCCESS) {
  436.     RequestDone(requestPtr->diskPtr, requestPtr, status, 0);
  437.     }
  438.     return TRUE;
  439. }
  440.  
  441. /*
  442.  *----------------------------------------------------------------------
  443.  *
  444.  * DevXylogics450Init --
  445.  *
  446.  *    Initialize a Xylogics controller.
  447.  *
  448.  * Results:
  449.  *    A NIL pointer if the controller does not exists. Otherwise a pointer
  450.  *    the the XylogicsController stucture.
  451.  *
  452.  * Side effects:
  453.  *    Map the controller into kernel virtual space.
  454.  *    Allocate buffer space associated with the controller.
  455.  *    Do a hardware reset of the controller.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459. ClientData
  460. DevXylogics450Init(cntrlrPtr)
  461.     DevConfigController *cntrlrPtr;    /* Config info for the controller */
  462. {
  463.     XylogicsController *xyPtr;    /* Xylogics specific state */
  464.     register volatile XylogicsRegs *regsPtr;/* Control registers for Xylogics */
  465.     char x;                /* Used when probing the controller */
  466.     int    i;
  467.     ReturnStatus status;
  468.     Address    addr;
  469.  
  470.  
  471.     /*
  472.      * Poke at the controller's registers to see if it works
  473.      * or we get a bus error.
  474.      */
  475.     regsPtr = (volatile XylogicsRegs *) cntrlrPtr->address;
  476.     status = Mach_Probe(sizeof(regsPtr->resetUpdate),
  477.              (char *) &(regsPtr->resetUpdate), (char *) &x);
  478.     if (status != SUCCESS) {
  479.     return DEV_NO_CONTROLLER;
  480.     }
  481.     status = Mach_Probe(sizeof(regsPtr->addrLow), "x",
  482.                 (char *) &(regsPtr->addrLow));
  483.     if (status == SUCCESS) {
  484.     status = Mach_Probe(sizeof(regsPtr->addrLow),
  485.                 (char *) &(regsPtr->addrLow), &x);
  486.     }
  487.     if (status != SUCCESS || (x != 'x') ) {
  488.     return DEV_NO_CONTROLLER;
  489.     }
  490.  
  491.     /*
  492.      * Allocate and initialize the controller state info.
  493.      */
  494.     xyPtr = (XylogicsController *)malloc(sizeof(XylogicsController));
  495.     bzero((char *) xyPtr, sizeof(XylogicsController));
  496.     xylogics[cntrlrPtr->controllerID] = xyPtr;
  497.     xyPtr->magic = XY_CNTRLR_STATE_MAGIC;
  498.     xyPtr->busy = FALSE;
  499.     xyPtr->regsPtr = regsPtr;
  500.     xyPtr->number = cntrlrPtr->controllerID;
  501.     xyPtr->requestPtr = (Request *) NIL;
  502.     /*
  503.      * Allocate the mapped DMA memory for the IOPB. This memory should not
  504.      * be freed unless the controller is not going to be accessed again.
  505.      */
  506.     addr = VmMach_DMAAlloc(sizeof(XylogicsIOPB), malloc(sizeof(XylogicsIOPB)));
  507.     if (addr == (Address) NIL) {
  508.     panic("DevXylogics450Init: unable to allocate DMA memory.\n");
  509.     }
  510.     xyPtr->IOPBPtr = (volatile XylogicsIOPB *) addr;
  511.     /*
  512.      * Initialize synchronization variables and set the controllers
  513.      * state to alive and not busy.
  514.      */
  515.     Sync_SemInitDynamic(&xyPtr->mutex,"Dev:xylogics mutex");
  516.     xyPtr->numSpecialWaiting = 0;
  517.     xyPtr->ctrlQueues = Dev_CtrlQueuesCreate(&xyPtr->mutex, xyEntryAvailProc);
  518.  
  519.     for (i = 0 ; i < XYLOGICS_MAX_DISKS ; i++) {
  520.      xyPtr->disks[i] =  (XylogicsDisk *) NIL;
  521.     }
  522.     ResetController(regsPtr);
  523.     return( (ClientData) xyPtr);
  524. }
  525.  
  526. /*
  527.  *----------------------------------------------------------------------
  528.  *
  529.  * ReleaseProc --
  530.  *
  531.  *    Device release proc for controller.
  532.  *
  533.  * Results:
  534.  *    None.
  535.  *
  536.  * Side effects:
  537.  *    None.
  538.  *
  539.  *----------------------------------------------------------------------
  540.  */
  541. static ReturnStatus
  542. ReleaseProc(handlePtr)
  543.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  544. {
  545.     PartitionDisk    *pdiskPtr = (PartitionDisk *) handlePtr;
  546.     free((char *) pdiskPtr);
  547.     return SUCCESS;
  548. }
  549.  
  550. /*
  551.  *----------------------------------------------------------------------
  552.  *
  553.  * IOControlProc --
  554.  *
  555.  *      Do a special operation on a raw SMD Disk.
  556.  *
  557.  * Results:
  558.  *      None.
  559.  *
  560.  * Side effects:
  561.  *      None.
  562.  *
  563.  *----------------------------------------------------------------------
  564.  */
  565.  
  566. /*ARGSUSED*/
  567. static ReturnStatus
  568. IOControlProc(handlePtr, ioctlPtr, replyPtr)
  569.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  570.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  571.     Fs_IOReply *replyPtr;    /* Size of outBuffer and returned signal */
  572. {
  573.  
  574.      switch (ioctlPtr->command) {
  575.     case    IOC_REPOSITION:
  576.         /*
  577.          * Reposition is ok
  578.          */
  579.         return(SUCCESS);
  580.         /*
  581.          * No disk specific bits are set this way.
  582.          */
  583.     case    IOC_GET_FLAGS:
  584.     case    IOC_SET_FLAGS:
  585.     case    IOC_SET_BITS:
  586.     case    IOC_CLEAR_BITS:
  587.         return(SUCCESS);
  588.  
  589.     case    IOC_GET_OWNER:
  590.     case    IOC_SET_OWNER:
  591.         return(GEN_NOT_IMPLEMENTED);
  592.  
  593.     case    IOC_TRUNCATE:
  594.         return(GEN_INVALID_ARG);
  595.  
  596.     case    IOC_LOCK:
  597.     case    IOC_UNLOCK:
  598.         return(GEN_NOT_IMPLEMENTED);
  599.  
  600.     case    IOC_NUM_READABLE:
  601.         return(GEN_NOT_IMPLEMENTED);
  602.  
  603.     case    IOC_MAP:
  604.         return(GEN_NOT_IMPLEMENTED);
  605.         
  606.     default:
  607.         return(GEN_INVALID_ARG);
  608.     }
  609. }
  610.  
  611.  
  612. /*
  613.  *----------------------------------------------------------------------
  614.  *
  615.  * BlockIOProc --
  616.  *
  617.  *    Start a block IO operations on a SMD disk attach to a xylogics 
  618.  *    controller.
  619.  *
  620.  * Results:
  621.  *    None.
  622.  *
  623.  * Side effects:
  624.  *    None.
  625.  *
  626.  *----------------------------------------------------------------------
  627.  */
  628. static ReturnStatus
  629. BlockIOProc(handlePtr, requestPtr) 
  630.     DevBlockDeviceHandle    *handlePtr; /* Handle pointer of device. */
  631.     DevBlockDeviceRequest *requestPtr; /* IO Request to be performed. */
  632. {
  633.     PartitionDisk    *pdiskPtr = (PartitionDisk *) handlePtr;
  634.     register XylogicsDisk *diskPtr = pdiskPtr->diskPtr;
  635.     register Request    *reqPtr;
  636.  
  637.     reqPtr = (Request *) requestPtr->ctrlData;
  638.     if (requestPtr->operation == FS_READ) {
  639.     reqPtr->command = XY_READ;
  640.     } else {
  641.     reqPtr->command = XY_WRITE;
  642.     }
  643.     reqPtr->diskPtr = diskPtr;
  644.     FillInDiskTransfer(pdiskPtr, requestPtr->startAddress, 
  645.             (unsigned) requestPtr->bufferLen,
  646.             &(reqPtr->diskAddress), &(reqPtr->numSectors));
  647.     reqPtr->buffer = requestPtr->buffer;
  648.     reqPtr->retries = 0;
  649.     reqPtr->requestPtr = requestPtr;
  650.     Dev_QueueInsert(diskPtr->queue, (List_Links *) reqPtr);
  651.     return SUCCESS;
  652. }
  653.  
  654. /*
  655.  *----------------------------------------------------------------------
  656.  *
  657.  * xyIdleCheck --
  658.  *
  659.  *    Routine for the Disk Stats module to use to determine the idleness
  660.  *    for a disk.
  661.  *
  662.  * Results:
  663.  *    TRUE if the disk pointed to by clientData is idle, FALSE otherwise.
  664.  *
  665.  * Side effects:
  666.  *    None.
  667.  *
  668.  *----------------------------------------------------------------------
  669.  */
  670. /*ARGSUSED*/
  671. static Boolean
  672. xyIdleCheck(clientData, diskStatsPtr) 
  673.     ClientData    clientData;
  674.     DevDiskStats    *diskStatsPtr;    /* Unused for xylogics. */
  675. {
  676.     XylogicsDisk *diskPtr = (XylogicsDisk *) clientData;
  677.     return (!diskPtr->xyPtr->busy);
  678. }
  679.  
  680.  
  681. /*
  682.  *----------------------------------------------------------------------
  683.  *
  684.  * DevXylogics450DiskAttach --
  685.  *
  686.  *      Initialize a device hanging off an Xylogics controller. 
  687.  *
  688.  * Results:
  689.  *    A DevBlockDeviceHanlde for this disk.
  690.  *
  691.  * Side effects:
  692.  *    Disks:  The label sector is read and the partitioning of
  693.  *    the disk is set up.  The partitions correspond to device
  694.  *    files of the same type but with different unit number.
  695.  *
  696.  *----------------------------------------------------------------------
  697.  */
  698. DevBlockDeviceHandle *
  699. DevXylogics450DiskAttach(devicePtr)
  700.     Fs_Device        *devicePtr;    /* Device to attach. */
  701. {
  702.     ReturnStatus error;
  703.     XylogicsController *xyPtr;    /* Xylogics specific controller state */
  704.     register XylogicsDisk *diskPtr;
  705.     PartitionDisk    *pdiskPtr;    /* Partitioned disk pointer. */
  706.     int        controllerID;
  707.     int        diskNumber;
  708.  
  709.     controllerID = XYLOGICS_CTRL_NUM_FROM_DEVUNIT(devicePtr->unit);
  710.     diskNumber = XYLOGICS_DISK_NUM_FROM_DEVUNIT(devicePtr->unit);
  711. /* XXX */ printf("XyDiskAttach unit 0x%x ctrlr %d disk %d\n",
  712.                    devicePtr->unit, controllerID, diskNumber);
  713.     xyPtr = xylogics[controllerID];
  714.     if (xyPtr == (XylogicsController *)NIL ||
  715.     xyPtr == (XylogicsController *)0 ||
  716.     xyPtr->magic != XY_CNTRLR_STATE_MAGIC ||
  717.     diskNumber > XYLOGICS_MAX_DISKS) {
  718.     return ((DevBlockDeviceHandle *) NIL);
  719.     }
  720.     /*
  721.      * Set up a slot in the disk list. We do a malloc before we grap the
  722.      * MASTER_LOCK().
  723.      */
  724.     diskPtr = (XylogicsDisk *) malloc(sizeof(XylogicsDisk));
  725.     bzero((char *) diskPtr, sizeof(XylogicsDisk));
  726.     diskPtr->magic = XY_DISK_STATE_MAGIC;
  727.     diskPtr->xyPtr = xyPtr;
  728.     diskPtr->xyDriveType = 0;
  729.     diskPtr->slaveID = diskNumber;
  730.     diskPtr->queue = Dev_QueueCreate(xyPtr->ctrlQueues, 1, 
  731.                 DEV_QUEUE_FIFO_INSERT, (ClientData) diskPtr);
  732.  
  733.     MASTER_LOCK(&(xyPtr->mutex));
  734.     if (xyPtr->disks[diskNumber] == (XylogicsDisk *) NIL) {
  735.     /*
  736.      * See if the disk is really there.
  737.      */
  738.     xyPtr->disks[diskNumber] = diskPtr;
  739.     error = TestDisk(xyPtr, diskPtr);
  740.     if (error == SUCCESS) {
  741.         /*
  742.          * Look at the zero'th sector for disk information.  This also
  743.          * sets the drive type with the controller.
  744.          */
  745.         error = ReadDiskLabel(xyPtr, diskPtr);
  746.     }
  747.  
  748.     if (error != SUCCESS) {
  749.         xyPtr->disks[diskNumber] =  (XylogicsDisk *) NIL;
  750.         MASTER_UNLOCK(&(xyPtr->mutex));
  751.         Dev_QueueDestroy(diskPtr->queue);
  752.         free((Address)diskPtr);
  753.         return ((DevBlockDeviceHandle *) NIL);
  754.     } 
  755.     MASTER_UNLOCK(&(xyPtr->mutex));
  756.     /* 
  757.      * Register the disk with the disk stats module. 
  758.      */
  759.     {
  760.         Fs_Device    rawDevice;
  761.         char    name[128];
  762.  
  763.         rawDevice =  *devicePtr;
  764.         rawDevice.unit = rawDevice.unit & ~0xf;
  765.         (void) sprintf(name, "xy%d-%d", xyPtr->number, diskPtr->slaveID);
  766.         diskPtr->diskStatsPtr = DevRegisterDisk(&rawDevice, name, 
  767.                    xyIdleCheck, (ClientData) diskPtr);
  768.     }
  769.     } else {
  770.     /*
  771.      * The disk already exists. Use it.
  772.      */
  773.     MASTER_UNLOCK(&(xyPtr->mutex));
  774.     Dev_QueueDestroy(diskPtr->queue);
  775.     free((Address)diskPtr);
  776.     diskPtr = xyPtr->disks[diskNumber];
  777.     }
  778.     pdiskPtr = (PartitionDisk *) malloc(sizeof(*pdiskPtr));
  779.     bzero((char *) pdiskPtr, sizeof(*pdiskPtr));
  780.     pdiskPtr->handle.blockIOProc = BlockIOProc;
  781.     pdiskPtr->handle.IOControlProc = IOControlProc;
  782.     pdiskPtr->handle.releaseProc = ReleaseProc;
  783.     pdiskPtr->handle.minTransferUnit = DEV_BYTES_PER_SECTOR;
  784.     pdiskPtr->handle.maxTransferSize = FS_BLOCK_SIZE;
  785.     pdiskPtr->partition = DISK_IS_PARTITIONED(devicePtr) ? 
  786.                     DISK_PARTITION(devicePtr) : 
  787.                     WHOLE_DISK_PARTITION;
  788.     pdiskPtr->diskPtr = diskPtr;
  789.     return ((DevBlockDeviceHandle *) pdiskPtr);
  790. }
  791.  
  792. /*
  793.  *----------------------------------------------------------------------
  794.  *
  795.  * ResetController --
  796.  *
  797.  *    Reset the controller.  This is done by reading the reset/update
  798.  *    register of the controller.
  799.  *
  800.  * Results:
  801.  *    None.
  802.  *
  803.  * Side effects:
  804.  *    Reset the controller.
  805.  *
  806.  *----------------------------------------------------------------------
  807.  */
  808. static void
  809. ResetController(regsPtr)
  810.     volatile XylogicsRegs *regsPtr;
  811. {
  812.     char x;
  813.     x = regsPtr->resetUpdate;
  814. #ifdef lint
  815.     regsPtr->resetUpdate = x;
  816. #endif
  817.     MACH_DELAY(100);
  818.     return;
  819. }
  820.  
  821. /*
  822.  *----------------------------------------------------------------------
  823.  *
  824.  * TestDisk --
  825.  *
  826.  *    Get a drive's status to see if it exists.
  827.  *
  828.  * Results:
  829.  *    SUCCESS if the device is ok, DEV_OFFLINE otherwise.
  830.  *
  831.  * Side effects:
  832.  *    none.
  833.  *
  834.  *----------------------------------------------------------------------
  835.  */
  836. static ReturnStatus
  837. TestDisk(xyPtr, diskPtr)
  838.     XylogicsController *xyPtr;
  839.     XylogicsDisk *diskPtr;
  840. {
  841.     register ReturnStatus status;
  842.     Request    request;
  843.  
  844.     bzero((char *) &request, sizeof(request));
  845.  
  846.     request.command = XY_READ_STATUS;
  847.     request.diskPtr = diskPtr;
  848.  
  849.     (void) SendCommand(diskPtr, &request, TRUE);
  850.  
  851. #ifdef notdef
  852.     printf("TestDisk:\n");
  853.     printf("Xylogics-%d disk %d\n", xyPtr->number, diskPtr->slaveID);
  854.     printf("Drive Status Byte %x\n", xyPtr->IOPBPtr->numSectLow);
  855.     printf("Drive Type %d: Cyls %d Heads %d Sectors %d\n",
  856.              diskPtr->xyDriveType,
  857.              xyPtr->IOPBPtr->cylHigh << 8 | xyPtr->IOPBPtr->cylLow,
  858.              xyPtr->IOPBPtr->head, xyPtr->IOPBPtr->sector);
  859.     printf("Bytes Per Sector %d, Num sectors %d\n",
  860.             xyPtr->IOPBPtr->dataAddrHigh << 8 |
  861.             xyPtr->IOPBPtr->dataAddrLow,
  862.             xyPtr->IOPBPtr->relocLow);
  863.     MACH_DELAY(1000000);
  864. #endif notdef
  865.     /*
  866.      * If all the status bits are low then the drive is ok.
  867.      */
  868.     if (xyPtr->IOPBPtr->numSectLow == 0) {
  869.         status = SUCCESS;
  870.     } else if (xyPtr->IOPBPtr->numSectLow == 0x20) {
  871.         printf("Warning: Xylogics-%d disk %d write protected\n",
  872.                     xyPtr->number, diskPtr->slaveID);
  873.         status = SUCCESS;
  874.     } else {
  875.         status = DEV_OFFLINE;
  876.     }
  877.  
  878.     return(status);
  879. }
  880.  
  881. /*
  882.  *----------------------------------------------------------------------
  883.  *
  884.  * ReadDiskLabel --
  885.  *
  886.  *    Read the label of the disk and record the partitioning info.
  887.  *
  888.  *     This should also check the Drive Type written on sector zero
  889.  *    of cylinder zero.  Use the Read Drive Status command for this.
  890.  *
  891.  * Results:
  892.  *    None.
  893.  *
  894.  * Side effects:
  895.  *    Define the disk partitions that determine which part of the
  896.  *    disk each different disk device uses.
  897.  *
  898.  *----------------------------------------------------------------------
  899.  */
  900. static ReturnStatus
  901. ReadDiskLabel(xyPtr, diskPtr)
  902.     XylogicsController *xyPtr;
  903.     XylogicsDisk *diskPtr;
  904. {
  905.     register ReturnStatus error ;
  906.     Sun_DiskLabel *diskLabelPtr;
  907.     Dev_DiskAddr diskAddr;
  908.     int part;
  909.     Request    request;
  910.     XylogicsSectorHeader    *headerPtr;    /* Sector header info */
  911.     char labelBuffer[DEV_BYTES_PER_SECTOR + 8]; /* Buffer for reading the
  912.                          * disk label into. The
  913.                          * buffer has 8 extra bytes
  914.                          * reading low-level sector 
  915.                          * info. */
  916.  
  917.  
  918.     /*
  919.      * Do a low level read that includes sector header info and ecc codes.
  920.      * This is done so we can learn the drive type needed in other commands.
  921.      */
  922.     diskAddr.head = 0;
  923.     diskAddr.sector = 0;
  924.     diskAddr.cylinder = 0;
  925.  
  926.     bzero((char *) &request, sizeof(request));
  927.     request.command = XY_RAW_READ;
  928.     request.diskPtr = diskPtr;
  929.     request.diskAddress = diskAddr;
  930.     request.numSectors = 1;
  931.     request.buffer = labelBuffer;
  932.  
  933.     error = SendCommand(diskPtr, &request, TRUE);
  934.     if (error != SUCCESS) {
  935.     printf("Xylogics-%d: disk%d, couldn't read the label\n",
  936.                  xyPtr->number, diskPtr->slaveID);
  937.     } else {
  938. /*XXX*/    printf("Header Bytes <%x, %x, %x, %x>\n", labelBuffer[0],
  939.                labelBuffer[1], labelBuffer[2], labelBuffer[3]);
  940.     headerPtr = (XylogicsSectorHeader *)labelBuffer;
  941.     diskPtr->xyDriveType = headerPtr->driveType;
  942.     diskLabelPtr = (Sun_DiskLabel *)(&labelBuffer[4]);
  943.  
  944.     printf("Label magic <%x>\n", diskLabelPtr->magic);
  945.     printf("Drive type %x\n", diskPtr->xyDriveType);
  946.     if (diskLabelPtr->magic == SUN_DISK_MAGIC) {
  947.         printf("Xylogics-%d disk%d: %s\n", xyPtr->number, diskPtr->slaveID,
  948.                     diskLabelPtr->asciiLabel);
  949.         diskPtr->numCylinders = diskLabelPtr->numCylinders;
  950.         diskPtr->numHeads = diskLabelPtr->numHeads;
  951.         diskPtr->numSectors = diskLabelPtr->numSectors;
  952.     
  953.         printf(" Partitions ");
  954.         for (part = 0; part < DEV_NUM_DISK_PARTS; part++) {
  955.         diskPtr->map[part].firstCylinder =
  956.             diskLabelPtr->map[part].cylinder;
  957.         diskPtr->map[part].numCylinders =
  958.             diskLabelPtr->map[part].numBlocks /
  959.             (diskLabelPtr->numHeads * diskLabelPtr->numSectors) ;
  960.         printf(" (%d,%d)", diskPtr->map[part].firstCylinder,
  961.                        diskPtr->map[part].numCylinders);
  962.         }
  963.         printf("\n");
  964.         /*
  965.          * Now that we know what the disk is like, we have to make sure
  966.          * that the controller does also.  The set parameters command
  967.          * sets the number of heads, sectors, and cylinders for the
  968.          * drive type.  The minus 1 is required because the controller
  969.          * numbers from zero and these parameters are upper bounds.
  970.          */
  971.         diskAddr.head = diskPtr->numHeads - 1;
  972.         diskAddr.sector = diskPtr->numSectors - 1;
  973.         diskAddr.cylinder = diskPtr->numCylinders - 1;
  974.  
  975.         bzero((char *) &request, sizeof(request));
  976.         request.command = XY_SET_DRIVE_SIZE;
  977.         request.diskPtr = diskPtr;
  978.         request.diskAddress = diskAddr;
  979.  
  980.     /* XXX */ printf("XY_SET_DRIVE_SIZE %d/%d/%d\n", diskAddr.cylinder, diskAddr.head, diskAddr.sector);
  981.  
  982.         error = SendCommand(diskPtr, &request, TRUE);
  983.         if (error != SUCCESS) {
  984.         printf("Xylogics-%d: disk%d, couldn't set drive size\n",
  985.                      xyPtr->number, diskPtr->slaveID);
  986.         }
  987.     } else {
  988.         printf("Xylogics-%d Disk %d, Unsupported label, magic = <%x>\n",
  989.                    xyPtr->number, diskPtr->slaveID,
  990.                    diskLabelPtr->magic);
  991.         error = FAILURE;
  992.     }
  993.     }
  994.     return(error);
  995. }
  996.  
  997.  
  998. #if 0
  999. /*
  1000.  *----------------------------------------------------------------------
  1001.  *
  1002.  *  VerifySectorHeader
  1003.  *    Checks the low-level sector header information against the
  1004.  *    logical address of the sector.
  1005.  *
  1006.  * Results:
  1007.  *    Returns 1 if sector header is ok.
  1008.  *
  1009.  * Side effects:
  1010.  *    None.
  1011.  *
  1012.  *----------------------------------------------------------------------
  1013.  */
  1014. static Boolean
  1015. VerifySectorHeader(diskAddrPtr, buffer)
  1016.     Dev_DiskAddr *diskAddrPtr;        /* Disk disk address of
  1017.                      * the first sector to transfer */
  1018.     char *buffer;            /* Buffer with sector plus 8 bytes.
  1019.                      * 4 bytes before, 4 bytes after. */
  1020. {
  1021.     Dev_DiskAddr checkAddr;
  1022.     XylogicsSectorHeader *headerPtr;
  1023.  
  1024.     headerPtr = (XylogicsSectorHeader *)buffer;
  1025.     checkAddr.cylinder = (headerPtr->cylHigh << 8) | headerPtr->cylLow ;
  1026.     checkAddr.head = headerPtr->head;
  1027.     checkAddr.sector = (headerPtr->sectorHigh << 8) | headerPtr->sectorLow;;
  1028.  
  1029.     if (checkAddr.cylinder != diskAddrPtr->cylinder ||
  1030.     checkAddr.head != diskAddrPtr->head ||
  1031.     checkAddr.sector != diskAddrPtr->sector) {
  1032.     printf("XY: Bad Sector Header? bytes <");
  1033.     printf("%x %x %x %x", buffer[1], buffer[0], buffer[3], buffer[2]);
  1034.     printf(">");
  1035.     printf(" Logical Addr [%d,%d,%d]\n",
  1036.          diskAddrPtr->cylinder,
  1037.          diskAddrPtr->head,
  1038.          diskAddrPtr->sector);
  1039.     return 0;
  1040.     } else {
  1041.     return 1;
  1042.     }
  1043. }
  1044. #endif
  1045.  
  1046.  
  1047. /*
  1048.  *----------------------------------------------------------------------
  1049.  *
  1050.  *  FillInDiskTransfer
  1051.  *    Fill in the disk address and number of sectors of a command.
  1052.  *
  1053.  * Results:
  1054.  *    None.
  1055.  *
  1056.  * Side effects:
  1057.  *    The number of sectors to transfer gets trimmed down if it would
  1058.  *    cross into the next partition.
  1059.  *
  1060.  *----------------------------------------------------------------------
  1061.  */
  1062. static void
  1063. FillInDiskTransfer(pdiskPtr, startAddress, length, diskAddrPtr, numSectorsPtr)
  1064.     PartitionDisk    *pdiskPtr;    /* Target Disk Partition. */
  1065.     unsigned int    startAddress;    /* Starting offset in bytes.*/
  1066.     unsigned int    length;        /* Length in bytes. */
  1067.     Dev_DiskAddr *diskAddrPtr;        /* Disk disk address of
  1068.                      * the first sector to transfer */
  1069.     int *numSectorsPtr;            /* The number
  1070.                      * of sectors to transferred. */
  1071. {
  1072.     XylogicsDisk *diskPtr;    /* State of the disk */
  1073.     int totalSectors;    /* The total number of sectors to transfer */
  1074.     int lastSector;    /* Last sector of the partition */
  1075.     int startSector;    /* The first sector of the transfer */
  1076.     int    part;        /* Partition number. */
  1077.     int    cylinderSize;    /* Size of a cylinder in sectors. */
  1078.  
  1079.     diskPtr = pdiskPtr->diskPtr;
  1080.     part = pdiskPtr->partition;
  1081.     cylinderSize = diskPtr->numHeads * diskPtr->numSectors;
  1082.     /*
  1083.      * Do bounds checking to keep the I/O within the partition.
  1084.      * sectorZero is the sector number of the first sector in the partition,
  1085.      * lastSector is the sector number of the last sector in the partition.
  1086.      * (These sector numbers are relative to the start of the partition.)
  1087.      */
  1088.     lastSector = diskPtr->map[part].numCylinders * cylinderSize - 1;
  1089.     totalSectors = length/DEV_BYTES_PER_SECTOR;
  1090.  
  1091.     startSector = startAddress / DEV_BYTES_PER_SECTOR;
  1092.  
  1093.     if (startSector > lastSector) {
  1094.     /*
  1095.      * The offset is past the end of the partition.
  1096.      */
  1097.     *numSectorsPtr = 0;
  1098.     printf("Warning: XylogicsDiskIO: Past end of partition %d\n",
  1099.                 part);
  1100.     return;
  1101.     } else if ((startSector + totalSectors - 1) > lastSector) {
  1102.     /*
  1103.      * The transfer is at the end of the partition.  Reduce the
  1104.      * sector count so there is no overrun.
  1105.      */
  1106.     totalSectors = lastSector - startSector + 1;
  1107.     printf("Warning: XylogicsDiskIO: Overrun partition %d\n",
  1108.                 part);
  1109.     }
  1110.     diskAddrPtr->cylinder = startSector / cylinderSize;
  1111.     startSector -= diskAddrPtr->cylinder * cylinderSize;
  1112.  
  1113.     diskAddrPtr->head = startSector / diskPtr->numSectors;
  1114.     startSector -= diskAddrPtr->head * diskPtr->numSectors;
  1115.  
  1116.     diskAddrPtr->sector = startSector;
  1117.  
  1118.     diskAddrPtr->cylinder += diskPtr->map[part].firstCylinder;
  1119.  
  1120.     if (diskAddrPtr->cylinder > diskPtr->numCylinders) {
  1121.     panic("Xylogics, bad cylinder # %d\n",
  1122.         diskAddrPtr->cylinder);
  1123.     }
  1124.     *numSectorsPtr = totalSectors;
  1125.     return;
  1126. }
  1127.  
  1128. /*
  1129.  *----------------------------------------------------------------------
  1130.  *
  1131.  * SetupIOPB --
  1132.  *
  1133.  *      Setup a IOPB for a command.  The IOPB can then
  1134.  *      be passed to SendCommand.  It specifies everything the
  1135.  *    controller needs to know to do a transfer, and it is updated
  1136.  *    with status information upon completion.
  1137.  *
  1138.  * Results:
  1139.  *    None.
  1140.  *
  1141.  * Side effects:
  1142.  *    Set the various fields in the control block.
  1143.  *
  1144.  *----------------------------------------------------------------------
  1145.  */
  1146. static void
  1147. SetupIOPB(command, diskPtr, diskAddrPtr, numSectors, address, interrupt,IOPBPtr)
  1148.     char command;            /* One of the Xylogics commands */
  1149.     XylogicsDisk *diskPtr;        /* Spefifies unit, drive type, etc */
  1150.     register Dev_DiskAddr *diskAddrPtr;    /* Head, sector, cylinder */
  1151.     int numSectors;            /* Number of sectors to transfer */
  1152.     register Address address;        /* Main memory address of the buffer */
  1153.     Boolean interrupt;            /* If TRUE use interupts, else poll */
  1154.     register volatile XylogicsIOPB *IOPBPtr;    /* I/O Parameter Block  */
  1155. {
  1156.     bzero((Address)IOPBPtr,sizeof(XylogicsIOPB));
  1157.  
  1158.     IOPBPtr->autoUpdate         = 1;
  1159.     IOPBPtr->relocation         = 1;
  1160.     IOPBPtr->doChaining         = 0;    /* New IOPB's are always end of chain */
  1161.     IOPBPtr->interrupt         = interrupt;
  1162.     IOPBPtr->command         = command;
  1163.  
  1164.     IOPBPtr->intrIOPB         = interrupt;    /* Polling or interrupt mode */
  1165.     IOPBPtr->autoSeekRetry    = 1;
  1166.     IOPBPtr->enableExtras    = 0;
  1167.     IOPBPtr->eccMode        = 2;    /* Correct soft errors for me, please */
  1168.  
  1169.     IOPBPtr->transferMode    = 0;    /* For words, not bytes */
  1170.     IOPBPtr->interleave        = 0;    /* For non interleaved */
  1171.     IOPBPtr->throttle        = 4;    /* max 32 words per burst */
  1172.  
  1173.     IOPBPtr->unit        = diskPtr->slaveID;
  1174.     IOPBPtr->driveType        = diskPtr->xyDriveType;
  1175.  
  1176.     if (diskAddrPtr != (Dev_DiskAddr *)NIL) {
  1177.     IOPBPtr->head        = diskAddrPtr->head;
  1178.     IOPBPtr->sector        = diskAddrPtr->sector;
  1179.     IOPBPtr->cylHigh    = (diskAddrPtr->cylinder & 0x0700) >> 8;
  1180.     IOPBPtr->cylLow        = (diskAddrPtr->cylinder & 0x00ff);
  1181.     }
  1182.  
  1183.     IOPBPtr->numSectHigh    = (numSectors & 0xff00) >> 8;
  1184.     IOPBPtr->numSectLow        = (numSectors & 0x00ff);
  1185.  
  1186.     if ((unsigned) address != 0 && (unsigned) address != (unsigned) NIL) {
  1187.     if ((unsigned) address < (unsigned) VMMACH_DMA_START_ADDR) {
  1188.         printf("%x: ", address);
  1189.         panic("Xylogics data address not in DMA space\n");
  1190.     }
  1191.     address = (Address)( (unsigned int)address - VMMACH_DMA_START_ADDR );
  1192.     IOPBPtr->relocHigh    = ((int)address & 0xff000000) >> 24;
  1193.     IOPBPtr->relocLow    = ((int)address & 0x00ff0000) >> 16;
  1194.     IOPBPtr->dataAddrHigh    = ((int)address & 0x0000ff00) >> 8;
  1195.     IOPBPtr->dataAddrLow    = ((int)address & 0x000000ff);
  1196.     }
  1197.     return;
  1198. }
  1199.  
  1200. /*
  1201.  *----------------------------------------------------------------------
  1202.  *
  1203.  * SendCommand --
  1204.  *
  1205.  *      Lower level routine to read or write an Xylogics device.  Use this
  1206.  *      to transfer a contiguous set of sectors.    The interface here
  1207.  *      is in terms of a particular Xylogics disk and the command to be
  1208.  *      sent.  This routine takes care of mapping its
  1209.  *      buffer into the special multibus memory area that is set up for
  1210.  *      Sun DMA.
  1211.  *
  1212.  * Results:
  1213.  *    An error code.
  1214.  *
  1215.  * Side effects:
  1216.  *    Those of the command (Read, write etc.)
  1217.  *
  1218.  *----------------------------------------------------------------------
  1219.  */
  1220. static ReturnStatus
  1221. SendCommand(diskPtr, requestPtr, wait)
  1222.     XylogicsDisk *diskPtr;    /* Unit, type, etc, of disk to send command. */
  1223.     Request     *requestPtr;    /* Command request block. */
  1224.     Boolean      wait;        /* Wait for the command to complete. */
  1225. {
  1226.     XylogicsController *xyPtr;    /* The Xylogics controller doing the command. */
  1227.     char command;        /* One of the standard Xylogics commands */
  1228.     Dev_DiskAddr *diskAddrPtr;    /* Head, sector, cylinder */
  1229.     int numSectors;        /* Number of sectors to transfer */
  1230.     Address address;        /* Main memory address of the buffer */
  1231.     ReturnStatus error;
  1232.     register volatile XylogicsRegs *regsPtr;    /* I/O registers */
  1233.     unsigned int IOPBAddr;
  1234.     int retries = 0;
  1235.  
  1236.     xyPtr = diskPtr->xyPtr;
  1237.  
  1238.     if (xyPtr->busy) {
  1239.     if (wait) {
  1240.         while (xyPtr->busy) {
  1241.         xyPtr->numSpecialWaiting++;
  1242.         Sync_MasterWait(&xyPtr->specialCmdWait, &xyPtr->mutex, FALSE);
  1243.         xyPtr->numSpecialWaiting--;
  1244.         }
  1245.     } else { 
  1246.         panic("Xylogics-%d: Software error, marked busy in SendCommand\n",
  1247.             xyPtr->number);
  1248.     }
  1249.     }
  1250.     xyPtr->busy = TRUE;
  1251.  
  1252.     command = requestPtr->command;
  1253.     diskAddrPtr = &requestPtr->diskAddress;
  1254.     address = requestPtr->buffer;
  1255.     numSectors = requestPtr->numSectors;
  1256.  
  1257.     /*
  1258.      * Without chaining the controller should always be idle at this
  1259.      * point.  
  1260.      */
  1261.     regsPtr = xyPtr->regsPtr;
  1262.     if (regsPtr->status & XY_GO_BUSY) {
  1263.     printf("Warning: Xylogics waiting for busy controller\n");
  1264.     (void)WaitForCondition(regsPtr, XY_GO_BUSY);
  1265.     }
  1266.     /*
  1267.      * Set up the I/O registers for the transfer.  All addresses given to
  1268.      * the controller must be relocated to the low megabyte so that the Sun
  1269.      * MMU will recognize them and map them back into the high megabyte of
  1270.      * the kernel's virtual address space.  (As circular as this sounds,
  1271.      * the level of indirection means the system can use any physical page
  1272.      * for an I/O buffer.)
  1273.      */
  1274.     if ((unsigned int)xyPtr->IOPBPtr < VMMACH_DMA_START_ADDR) {
  1275.     printf("%x: ", xyPtr->IOPBPtr);
  1276.     panic("Warning: Xylogics IOPB not in DMA space\n");
  1277.     xyPtr->busy = FALSE;
  1278.     return(FAILURE);
  1279.     }
  1280.     IOPBAddr = (unsigned int)xyPtr->IOPBPtr - VMMACH_DMA_START_ADDR;
  1281.     regsPtr->relocHigh = (IOPBAddr & 0xFF000000) >> 24;
  1282.     regsPtr->relocLow  = (IOPBAddr & 0x00FF0000) >> 16;
  1283.     regsPtr->addrHigh  = (IOPBAddr & 0x0000FF00) >>  8;
  1284.     regsPtr->addrLow   = (IOPBAddr & 0x000000FF);
  1285.  
  1286.     /*
  1287.      * If the command is going to transfer data be relocate the address
  1288.      * into DMA space. 
  1289.      */
  1290.     if ((address != (Address) 0) && (numSectors > 0)) {
  1291.     if (command == XY_RAW_READ || command == XY_RAW_WRITE) {
  1292.         xyPtr->dmaBufferSize = (DEV_BYTES_PER_SECTOR + 8) * numSectors;
  1293.     } else {
  1294.         xyPtr->dmaBufferSize = DEV_BYTES_PER_SECTOR  * numSectors;
  1295.     }
  1296.     xyPtr->dmaBuffer =  VmMach_DMAAlloc(xyPtr->dmaBufferSize, address);
  1297.     if (xyPtr->dmaBuffer == (Address) NIL) {
  1298.         panic("SendCommand: unable to allocate DMA memory.");
  1299.     }
  1300.     } else {
  1301.     xyPtr->dmaBufferSize = 0;
  1302.     }
  1303.  
  1304. retry:
  1305.     SetupIOPB(command, diskPtr, diskAddrPtr, numSectors, xyPtr->dmaBuffer, 
  1306.         !wait, xyPtr->IOPBPtr);
  1307. #ifdef notdef
  1308.     if (TRUE) {
  1309.     char *address;
  1310.     int    i;
  1311.     printf("IOBP bytes: ");
  1312.     address = (char *)xyPtr->IOPBPtr;
  1313.     for (i=0 ; i<24 ; i++) {
  1314.         printf("%x ", address[i] & 0xff);
  1315.     }
  1316.     printf("\n");
  1317.     }
  1318. #endif
  1319.     /*
  1320.      * Start up the controller
  1321.      */
  1322.     regsPtr->status = XY_GO_BUSY;
  1323.  
  1324.     if (wait) {
  1325.         /*
  1326.          * A synchronous command.  Wait here for the command to complete.
  1327.          */
  1328.         error = WaitForCondition(regsPtr, XY_GO_BUSY);
  1329.         if (error != SUCCESS) {
  1330.             printf("Xylogics-%d: couldn't wait for command to complete\n",
  1331.                                  xyPtr->number);
  1332.         } else {
  1333.             /*
  1334.              * Check for error status from the operation itself.
  1335.              */
  1336.             error = GetStatus(xyPtr);
  1337.             if (error == DEV_RETRY_ERROR && retries < 3) {
  1338.                 retries++;
  1339.         printf("Warning: Xylogics Retrying...\n");
  1340.                 goto retry;
  1341.             }
  1342.         }
  1343.     if (xyPtr->dmaBufferSize > 0) { 
  1344.         VmMach_DMAFree(xyPtr->dmaBufferSize, xyPtr->dmaBuffer);
  1345.         xyPtr->dmaBufferSize = 0;
  1346.     }
  1347.     xyPtr->busy = FALSE;
  1348.     StartNextRequest(xyPtr);
  1349.     } else { 
  1350.        /*
  1351.         * Store request for interrupt handler. 
  1352.     */
  1353.        xyPtr->requestPtr = requestPtr;
  1354.        error = SUCCESS;
  1355.     }
  1356.     return(error);
  1357. }
  1358.  
  1359. /*
  1360.  *----------------------------------------------------------------------
  1361.  *
  1362.  * GetStatus --
  1363.  *
  1364.  *    Tidy up after a Xylogics command by looking at status bytes from
  1365.  *    the device.
  1366.  *
  1367.  * Results:
  1368.  *    An error code from the recently completed transfer.
  1369.  *
  1370.  * Side effects:
  1371.  *    None.
  1372.  *
  1373.  *----------------------------------------------------------------------
  1374.  */
  1375. static ReturnStatus
  1376. GetStatus(xyPtr)
  1377.     XylogicsController *xyPtr;
  1378. {
  1379.     register ReturnStatus error = SUCCESS;
  1380.     register volatile XylogicsRegs *regsPtr;
  1381.     register volatile XylogicsIOPB *IOPBPtr;
  1382.  
  1383.     regsPtr = xyPtr->regsPtr;
  1384.     IOPBPtr = xyPtr->IOPBPtr;
  1385.     if ((regsPtr->status & XY_ERROR) || IOPBPtr->error) {
  1386.     if (regsPtr->status & XY_DBL_ERROR) {
  1387.         printf("Xylogics-%d double error %x\n", xyPtr->number,
  1388.                     IOPBPtr->errorCode);
  1389.         error = DEV_HARD_ERROR;
  1390.     } else {
  1391.         switch (IOPBPtr->errorCode) {
  1392.         case XY_NO_ERROR:
  1393.             error = SUCCESS;
  1394.             break;
  1395.         case XY_ERR_BAD_CYLINDER:
  1396.             printf("Xylogics bad cylinder # %d\n",
  1397.                  IOPBPtr->cylHigh << 8 | IOPBPtr->cylLow);
  1398.             error = DEV_HARD_ERROR;
  1399.             break;
  1400.         case XY_ERR_BAD_SECTOR:
  1401.             printf("Xylogics bad sector # %d\n", IOPBPtr->sector);
  1402.             error = DEV_HARD_ERROR;
  1403.             break;
  1404.         case XY_ERR_BAD_HEAD:
  1405.             printf("Xylogics bad head # %d\n", IOPBPtr->head);
  1406.             error = DEV_HARD_ERROR;
  1407.             break;
  1408.         case XY_ERR_ZERO_COUNT:
  1409.             printf("Xylogics zero count\n");
  1410.             error = DEV_HARD_ERROR;
  1411.             break;
  1412.         case XY_ERR_INTR_PENDING:
  1413.         case XY_ERR_BUSY_CONFLICT:
  1414.         case XY_ERR_BAD_COMMAND:
  1415.         case XY_ERR_BAD_SECTOR_SIZE:
  1416.         case XY_ERR_SELF_TEST_A:
  1417.         case XY_ERR_SELF_TEST_B:
  1418.         case XY_ERR_SELF_TEST_C:
  1419.         case XY_ERR_SLIP_SECTOR:
  1420.         case XY_ERR_SLAVE_ACK:
  1421.         case XY_FORMAT_ERR_RUNT:
  1422.         case XY_FORMAT_ERR_BAD_SIZE:
  1423.         case XY_SOFT_ECC:
  1424.             panic("Stupid Xylogics error: 0x%x\n",
  1425.                         IOPBPtr->errorCode);
  1426.             error = DEV_HARD_ERROR;
  1427.             break;
  1428.         case  XY_SOFT_ERR_TIME_OUT:
  1429.         case  XY_SOFT_ERR_BAD_HEADER:
  1430.         case  XY_SOFT_ERR_ECC:
  1431.         case  XY_SOFT_ERR_NOT_READY:
  1432.         case  XY_SOFT_ERR_HEADER:
  1433.         case  XY_SOFT_ERR_FAULT:
  1434.         case  XY_SOFT_ERR_SEEK:
  1435.             error = DEV_RETRY_ERROR;
  1436.             printf("Warning: Retryable Xylogics error: 0x%x\n",
  1437.                 IOPBPtr->errorCode);
  1438.             break;
  1439.         case XY_WRITE_PROTECT_ON:
  1440.             printf("Xylogics-%d: ", xyPtr->number);
  1441.             printf("Warning: Write protected\n");
  1442.             error = GEN_NO_PERMISSION;
  1443.             break;
  1444.         case XY_SOFT_ECC_RECOVERED:
  1445.             printf("Xylogics-%d: ", xyPtr->number);
  1446.             printf("Warning: Soft ECC error recovered\n");
  1447.             error = SUCCESS;
  1448.             break;
  1449.         default:
  1450.             error = DEV_HARD_ERROR;
  1451.             break;
  1452.         }
  1453.     }
  1454.     /*
  1455.      * Reset the error by writing a 1 to the XY_ERROR bit.
  1456.      */
  1457.     if (regsPtr->status & XY_ERROR) {
  1458.         regsPtr->status = XY_ERROR;
  1459.     }
  1460.     }
  1461.     return(error);
  1462. }
  1463.  
  1464. /*
  1465.  *----------------------------------------------------------------------
  1466.  *
  1467.  * WaitForCondition --
  1468.  *
  1469.  *    Wait for the Xylogics controller to finish.  This is done by
  1470.  *    polling its GO_BUSY bit until it reads zero.
  1471.  *
  1472.  * Results:
  1473.  *    SUCCESS if it completed before a threashold time limit,
  1474.  *    DEV_TIMEOUT otherwise.
  1475.  *
  1476.  * Side effects:
  1477.  *    None.
  1478.  *
  1479.  *----------------------------------------------------------------------
  1480.  */
  1481. static ReturnStatus
  1482. WaitForCondition(regsPtr, condition)
  1483.     volatile XylogicsRegs *regsPtr;
  1484.     int condition;
  1485. {
  1486.     register int i;
  1487.     ReturnStatus status = DEV_TIMEOUT;
  1488.  
  1489.     for (i=0 ; i<XYLOGICS_WAIT_LENGTH ; i++) {
  1490.     if ((regsPtr->status & condition) == 0) {
  1491.         return(SUCCESS);
  1492.     } else if (regsPtr->status & XY_ERROR) {
  1493.         /*
  1494.          * Let GetStatus() figure out what happened
  1495.          */
  1496.         return(SUCCESS);
  1497.     }
  1498.     MACH_DELAY(10);
  1499.     }
  1500.     printf("Warning: Xylogics reset");
  1501.     ResetController(regsPtr);
  1502.     return(status);
  1503. }
  1504.  
  1505. /*
  1506.  *----------------------------------------------------------------------
  1507.  *
  1508.  * DevXylogics450Intr --
  1509.  *
  1510.  *    Handle interrupts from the Xylogics controller.   This routine
  1511.  *    may start any queued requests.
  1512.  *
  1513.  * Results:
  1514.  *    TRUE if an Xylogics controller was responsible for the interrupt
  1515.  *    and this routine handled it.
  1516.  *
  1517.  * Side effects:
  1518.  *    Usually a process is notified that an I/O has completed.
  1519.  *
  1520.  *----------------------------------------------------------------------
  1521.  */
  1522. Boolean
  1523. DevXylogics450Intr(clientData)
  1524.     ClientData    clientData;
  1525. {
  1526.     ReturnStatus error = SUCCESS;
  1527.     register XylogicsController *xyPtr;
  1528.     register volatile XylogicsRegs *regsPtr;
  1529.     register volatile XylogicsIOPB *IOPBPtr;
  1530.     Request    *requestPtr;
  1531.  
  1532.     xyPtr = (XylogicsController *) clientData;
  1533.     regsPtr = xyPtr->regsPtr;
  1534.     if (regsPtr->status & XY_INTR_PENDING) {
  1535.     MASTER_LOCK(&(xyPtr->mutex));
  1536.     /*
  1537.      * Reset the pending interrupt by writing a 1 to the
  1538.      * INTR_PENDING bit of the status register.
  1539.      */
  1540.     regsPtr->status = XY_INTR_PENDING;
  1541.     IOPBPtr = xyPtr->IOPBPtr;
  1542.     requestPtr = xyPtr->requestPtr;
  1543.     /*
  1544.      * Release the DMA buffer if command mapped one. 
  1545.      */
  1546.     if (xyPtr->dmaBufferSize > 0) {
  1547.         VmMach_DMAFree(xyPtr->dmaBufferSize, xyPtr->dmaBuffer);
  1548.         xyPtr->dmaBufferSize = 0;
  1549.     }
  1550.     if ((regsPtr->status & XY_ERROR) || IOPBPtr->error) {
  1551.         error = GetStatus(xyPtr);
  1552.         if (error == DEV_RETRY_ERROR) {
  1553.         requestPtr->retries++;
  1554.         if (requestPtr->retries < 3) {
  1555.             xyPtr->busy = FALSE;
  1556.             error = SendCommand(requestPtr->diskPtr, requestPtr,FALSE);
  1557.             if (error == SUCCESS) {
  1558.             MASTER_UNLOCK(&(xyPtr->mutex));
  1559.             return (TRUE);
  1560.             }
  1561.         }
  1562.         }
  1563.     }
  1564.     /*
  1565.      * For now there are no occasions where only part
  1566.      * of an I/O can complete.
  1567.      */
  1568.     xyPtr->busy = FALSE;
  1569.     RequestDone(requestPtr->diskPtr,requestPtr,error,requestPtr->numSectors);
  1570.     StartNextRequest(xyPtr);
  1571.     MASTER_UNLOCK(&(xyPtr->mutex));
  1572.     return(TRUE);
  1573.     }
  1574.     return(FALSE);
  1575. }
  1576.  
  1577.  
  1578. /*
  1579.  *----------------------------------------------------------------------
  1580.  *
  1581.  * RequestDone --
  1582.  *
  1583.  *    Mark a request as done by calling the request's doneProc. DMA memory
  1584.  *    is released.
  1585.  *
  1586.  * Results:
  1587.  *    None.
  1588.  *
  1589.  * Side effects:
  1590.  *    None.
  1591.  *
  1592.  *----------------------------------------------------------------------
  1593.  */
  1594.  
  1595. static void
  1596. RequestDone(diskPtr, requestPtr, status, numSectors)
  1597.     XylogicsDisk *diskPtr;
  1598.     Request    *requestPtr;
  1599.     ReturnStatus    status;
  1600.     int        numSectors;
  1601. {
  1602.     if (numSectors > 0) {
  1603.     if (requestPtr->requestPtr->operation == FS_READ) {
  1604.         diskPtr->diskStatsPtr->diskStats.diskReads += numSectors;
  1605.     } else {
  1606.         diskPtr->diskStatsPtr->diskStats.diskWrites += numSectors;
  1607.     }
  1608.     }
  1609.     MASTER_UNLOCK(&diskPtr->xyPtr->mutex);
  1610.     (requestPtr->requestPtr->doneProc)(requestPtr->requestPtr, status,
  1611.                 numSectors*DEV_BYTES_PER_SECTOR);
  1612.     MASTER_LOCK(&diskPtr->xyPtr->mutex);
  1613. }
  1614.  
  1615. /*
  1616.  *----------------------------------------------------------------------
  1617.  *
  1618.  * StartNextRequest --
  1619.  *
  1620.  *    Start the next request of a Xylogics450 controller.
  1621.  *
  1622.  * Results:
  1623.  *    None.
  1624.  *
  1625.  * Side effects:
  1626.  *    None.
  1627.  *
  1628.  *----------------------------------------------------------------------
  1629.  */
  1630. static void
  1631. StartNextRequest(xyPtr)
  1632.     XylogicsController *xyPtr;
  1633. {
  1634.     ClientData    clientData;
  1635.     List_Links *newRequestPtr;
  1636.     ReturnStatus    status;
  1637.  
  1638.      /*
  1639.      * If the controller is busy, just return.
  1640.      */
  1641.     if (xyPtr->busy) {
  1642.     return;
  1643.     }
  1644.     /*
  1645.      * If a SPECIAL command is waiting wake up the process to do the command.
  1646.      */
  1647.     if (xyPtr->numSpecialWaiting > 0) {
  1648.     Sync_MasterBroadcast(&xyPtr->specialCmdWait);
  1649.     return;
  1650.     }
  1651.     /* 
  1652.      * Otherwise process requests from the Queue. 
  1653.      */
  1654.     newRequestPtr = Dev_QueueGetNextFromSet(xyPtr->ctrlQueues,
  1655.                 DEV_QUEUE_ANY_QUEUE_MASK,&clientData);
  1656.     while (newRequestPtr != (List_Links *) NIL) {
  1657.     register Request *requestPtr;
  1658.     XylogicsDisk    *diskPtr;
  1659.  
  1660.     requestPtr = (Request *) newRequestPtr;
  1661.     diskPtr = (XylogicsDisk *) clientData;
  1662.  
  1663.     status = SendCommand(diskPtr, requestPtr, FALSE);
  1664.     if (status != SUCCESS) {
  1665.         RequestDone(requestPtr->diskPtr, requestPtr, status, 0);
  1666.         newRequestPtr = Dev_QueueGetNextFromSet(xyPtr->ctrlQueues,
  1667.                 DEV_QUEUE_ANY_QUEUE_MASK,&clientData);
  1668.     } else {
  1669.         break;
  1670.     }
  1671.     }
  1672.     return;
  1673. }
  1674.  
  1675.